// Oneself
#include "can.h"

BSP_CAN_Typedef bsp_can = {0};

void BSP_CAN_Init(void)
{
    /* CAN配置结构体 */
    can_parameter_struct can_parameter;
    can_filter_parameter_struct can_filter;

    /* 时钟使能 */
    rcu_periph_clock_enable(RCU_CAN0);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_AF);
    gpio_pin_remap_config(GPIO_CAN_PARTIAL_REMAP, ENABLE);           // 引脚重映射

    /* GPIO配置 */
    gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8);   // CAN_RX
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // CAN_TX
    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);//CAN_RS
    gpio_bit_reset(GPIOC, GPIO_PIN_13);

    /* CAN参数配置 */
    can_parameter.working_mode = CAN_NORMAL_MODE;  // 正常模式;
    can_parameter.auto_bus_off_recovery = DISABLE;  // 自动离线恢复
    can_parameter.auto_retrans = ENABLE;       // 禁止自动重传
    can_parameter.auto_wake_up = ENABLE;        // 自动唤醒
    can_parameter.rec_fifo_overwrite = DISABLE;    // FIFO不覆盖
    can_parameter.time_triggered = DISABLE;     // 非时间触发模式
    can_parameter.trans_fifo_order = DISABLE;   // 优先级由报文标识符决定
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_9TQ;
    can_parameter.time_segment_2 = CAN_BT_BS2_8TQ;
    can_parameter.prescaler = 4;                   // 分频系数
    can_init(CAN0, &can_parameter);

    /* 过滤器配置 */
    can_filter.filter_number = 0;
    can_filter.filter_mode = CAN_FILTERMODE_MASK;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    can_filter.filter_list_high = 0x0000;
    can_filter.filter_list_low = 0x0000;
    can_filter.filter_mask_high = 0x0000;
    can_filter.filter_mask_low = 0x0000;
    can_filter.filter_fifo_number = CAN_FIFO0;
    can_filter.filter_enable = ENABLE;
    can_filter_init(&can_filter);

    /* 中断配置 */
#if CAN_RX0_INT_ENABLE
    nvic_irq_enable(USBD_LP_CAN0_RX0_IRQn, 3, 0);
    can_interrupt_enable(CAN0, CAN_INT_RFNE0);
#endif

}

// 检查哪个 CAN 发送邮箱为空
uint8_t check_empty_can_mailbox(void) {
    if (CAN_TSTAT_TME0) {
        return CAN_MAILBOX0; // 邮箱 0 为空
    } else if (CAN_TSTAT_TME1) {
        return CAN_MAILBOX1; // 邮箱 1 为空
    } else if (CAN_TSTAT_TME2) {
        return CAN_MAILBOX2; // 邮箱 2 为空
    } else {
        return CAN_NOMAILBOX; // 没有邮箱为空
    }
}


void TxDataEmpty(uint8_t *msg, uint8_t len)
{
    for (uint8_t i = 0; i < len; i++)
    {
        bsp_can.CanTx.tx_data[i] = 0;
    }
}

/**
 * @brief       CAN 发送一组数据
 *   @note      发送格式固定为: 标准ID, 数据帧
 * @param       id      : 扩展ID(29位)
 * @param       msg     : 数据指针
 * @param       len     : 数据长度
 * @retval      发送状态 0, 成功; 1, 失败;
 */
ErrStatus can_send_msg(uint8_t *cmd, uint8_t len)
{
    uint32_t TxMailbox;
    uint16_t timeout = 0xFFF;
    uint8_t i = 0, j = 0, k = 0, l = 0, packNum = 0;

    /* 自动选择空闲邮箱 */
    // TxMailbox = check_empty_can_mailbox();
    // if(TxMailbox == CAN_NOMAILBOX){
    //     return ERROR; // 所有邮箱忙
    // }

    /* 清空发送缓冲区 */
    TxDataEmpty(cmd, len);

    // 除去ID地址和功能码后的数据长度
    j = len - 2;

    // 发送数据
    while(i < j)
    {
        // 数据个数
        k = j - i;

        // 填充缓存
        bsp_can.CanTx.tx_sfid = 0x00;
        bsp_can.CanTx.tx_efid = ((uint32_t)cmd[0] << 8) | (uint32_t)packNum;
        bsp_can.CanTx.tx_data[0] = cmd[1];
        bsp_can.CanTx.tx_ff = CAN_FF_STANDARD;
        bsp_can.CanTx.tx_ft = CAN_FT_DATA;

        // 小于8字节命令
        if(k < 8)
        {
            for(l=0; l < k; l++,i++) { bsp_can.CanTx.tx_data[l + 1] = cmd[i + 2]; } bsp_can.CanTx.tx_dlen = k + 1;
        }
        // 大于8字节命令，分包发送，每包数据最多发送8个字节
        else
        {
            for(l=0; l < 7; l++,i++) { bsp_can.CanTx.tx_data[l + 1] = cmd[i + 2]; } bsp_can.CanTx.tx_dlen = 8;
        }

        // 发送数据
        TxMailbox = can_message_transmit(CAN0, &bsp_can.CanTx);

        /* 等待传输完成 */
        while(can_transmit_states(CAN0, TxMailbox) != CAN_TRANSMIT_OK){
            if(timeout-- == 0){
                can_transmission_stop(CAN0, TxMailbox);
                return ERROR;
            }
        }

        // 记录发送的第几包的数据
        ++packNum;
    }
    return SUCCESS;
}

void can_send_data_msg(uint8_t id, uint8_t *msg, uint8_t len)
{
    uint32_t Mailbox;
    uint16_t timeout = 0xFFF;
    bsp_can.CanTx.tx_efid = 0x00;
    bsp_can.CanTx.tx_sfid = id;
    bsp_can.CanTx.tx_ff = CAN_FF_EXTENDED;
    bsp_can.CanTx.tx_ft = CAN_FT_DATA;
    bsp_can.CanTx.tx_dlen = len;
    for(uint8_t i = 0; i < len; i++){ bsp_can.CanTx.tx_data[i] = msg[i]; }
    Mailbox = can_message_transmit(CAN0, &bsp_can.CanTx);

    /* 等待传输完成 */
    while(can_transmit_states(CAN0, Mailbox) != CAN_TRANSMIT_OK){
        if(timeout-- == 0){
            can_transmission_stop(CAN0, Mailbox);
            return;
        }
    }
}
